#![allow(async_fn_in_trait)]
use std::sync::Arc;

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
pub use uuid::Uuid as PlayerUUID;
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct AuthInfo {
    pub username: String,
    pub uuid: PlayerUUID,
    pub access_token: String,
    pub refresh_token: String,
    pub is_online: bool,
}

pub trait AuthDB {
    type Error: std::error::Error + Send + Sync + 'static;
    fn get_auth(&self, name: &str) -> Result<Option<AuthInfo>, Self::Error>;
    fn save_auth(&self, auth: AuthInfo) -> Result<(), Self::Error>;
    fn remove_auth(&self, name: &str) -> Result<(), Self::Error>;
    fn list_all_auth(&self) -> Result<Vec<AuthInfo>, Self::Error>;
}
// FOR OFFLINE PLAYER
pub trait OfflineAuth {
    fn to_auth(name: &str, uuid: Option<PlayerUUID>) -> AuthInfo;
}

//FOR ONLINE PLAYER
pub trait OnlineAuth {}

//FOR DOWNLOADER INTERFACE
pub struct DownloadTask {
    pub url: String,
    pub path: String,
}
pub struct DownloaderStatus {
    pub speed: u64,
    pub active: u64,
    pub waiting: u64,
}
pub struct TaskStatus {
    pub total_size: u64,
    pub downloaded_size: u64,
    pub speed: u64,
    pub state: String,
}
pub trait Downloader {
    type Error: std::error::Error + Send + Sync + 'static;
    async fn add(&mut self, task: &[DownloadTask]) -> Result<(), Self::Error>;
    async fn pause(&self) -> Result<(), Self::Error>;
    async fn resume(&self) -> Result<(), Self::Error>;
    async fn cancel(&mut self) -> Result<(), Self::Error>;
    async fn get_status(&self) -> Result<(DownloaderStatus, Vec<TaskStatus>), Self::Error>;
}
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct MCVersion {
    pub version: String,
    pub type_: String,
    pub url: String,
    #[serde(with = "chrono::serde::ts_seconds")]
    pub time: DateTime<Utc>,
}
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct GameFile {
    pub path: String,
    pub size: u64,
    pub sha1: String,
    pub url: String,
}
pub trait GetVersion {
    const ROOT_URL: &str;
    const ASSET_URL: &str;
    type Error: std::error::Error + Send + Sync + 'static;
    async fn get_version_list(&self) -> Result<Vec<MCVersion>, Self::Error>;
    async fn get_file_list(&self, version: MCVersion) -> Result<Vec<GameFile>, Self::Error>;
}
pub trait FileCheck {
    type Error: std::error::Error + Send + Sync + 'static;
    fn check_file(&self, file: &GameFile) -> Result<bool, Self::Error>;
    fn check_notmatch_file(&self, files: &[GameFile]) -> Result<Vec<GameFile>, Self::Error>;
}
pub trait ConfigDB {
    type Error: std::error::Error + Send + Sync + 'static;
    fn get(&self) -> Result<Option<LauncherConfig>, Self::Error>;
    fn set(&self, config: &LauncherConfig) -> Result<(), Self::Error>;
}
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct LauncherConfig {
    pub rpc_url: String,
    pub rpc_secret: String,
    pub mc_folder: Vec<String>,
    pub jvm_args: Vec<String>,
    pub java_path: String,
}

pub trait BackEndImpl<HANDLE> {
    type Downloader: Downloader;
    type Database: AuthDB + ConfigDB;
    type Auth: OfflineAuth;
    type FileSystem: FileCheck;
    type VersionGetter: GetVersion;
    type Error: std::error::Error;

    fn new(
        downloader: Self::Downloader,
        database: Self::Database,
        auth: Self::Auth,
        filesystem: Self::FileSystem,
        versiongetter: Self::VersionGetter,
    ) -> Self;
    async fn start(self: Arc<Self>, ip: [u8; 4], port: u16) -> Result<HANDLE, Self::Error>;
}
